﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TheClerk.Forms
{
    /// <summary>
    /// Forms that a Clerk works with.
    /// </summary>
    /// <remarks>
    /// Every clerk works with forms -- be they cashiers
    /// (cash, check, money order, traveller's cheque, etc),
    /// recorders, library checkout clerks, or anything else.
    /// The only differentiation is what forms they put where, for how
    /// long.
    /// 
    /// The Form implements its own rules for determining when it has
    /// been "filled out".  The clerk Form.Glance()s at the form
    /// to ensure that it can be Clerk.Accept()ed -- which is what
    /// creates the Receipt (for our purposes, the Receipt is the form,
    /// timestamped).
    /// 
    /// The Form has an associated handling scheme, but this handling
    /// scheme is part of the Clerk's workflow.  (the clerk has an input
    /// chute for Forms, and determines its disposition based on the form
    /// type.)
    ///
    /// The Form doesn't implement its Fields, it merely provides access
    /// to them.  (so they're much more like properties.)
    /// </remarks>
    public abstract class Form
    {
        /// <summary>
        /// Check to see if all required fields are filled in
        /// </summary>
        /// <returns>true if it's ready to be signed</returns>
        public abstract bool isComplete { get; }

        /// <summary>
        /// Has this instance of this Form been processed by a Clerk?
        /// </summary>
        public bool received
        {
            get
            {
                if (_receipt != null)
                    return true;
                return false;
            }
        }

        public static Form GetForm(string toRetrieve)
        {
            return FormStore.Get(toRetrieve);
        }

        /// <summary>
        /// Ready the Form for transmission/signing/timestamping/submission
        /// </summary>
        /// <param name="submission">The Form to render into a signable blob</param>
        /// <returns>The rendered signable byte[] blob</returns>
        /// <remarks>
        /// TODO This will be DER.
        /// This will be the Form structure itself as signed by the local
        /// Clerk, plus the field data, all wrapped in a signature by the
        /// supplicant.  (i.e., it's the serialization of the filled-in
        /// Form structure.)
        /// </remarks>
        public static byte[] Canonize(Form submission)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Get an array of strings that represent the fields of the form
        /// </summary>
        /// <returns>array of strings that name this.fields[]</returns>
        public virtual string[] GetFieldNames()
        {
            string[] fieldnames = new string[formfields.Count];
            int temp = 0;
            foreach (KeyValuePair<string, FieldValue> s in formfields)
                temp++;
            int nextindex = 0;

            foreach (KeyValuePair<string, FieldValue> s in formfields)
                fieldnames[nextindex++] = s.Key;
            return fieldnames;
        }

        /// <summary>
        /// Get the FieldValue of a key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual FieldValue GetValue(string key)
        {
            try
            {
                return formfields[key];
            }
            catch { return null; }
        }

        /// <summary>
        /// Forms can have multiple form numbers, if they're referenced from
        /// different places.
        /// </summary>
        /// <param name="tocheck"></param>
        /// <param name="asofdate"></param>
        /// <remarks>Forms can have multiple form numbers and Names, if they're
        /// referenced from different places or are named different things
        /// in different cultures.</remarks>
        /// <returns>Boolean: Does this claim the name tocheck as of the given
        /// date?</returns>
        internal virtual bool MyFormID(string tocheck, DateTime asofdate)
        {
            bool possible = false;
            foreach (string s in _formID)
            {
                if (s == tocheck)
                {
                    possible = true;
                    break;
                }
            }

            if (!possible)
                return false;

            if (asofdate.CompareTo(initiationdate) >= 0 && asofdate.CompareTo(expirationdate) <= 0)
            {
                return true;
            }

            return false;
        }

        internal virtual bool MyFormID(string tocheck)
        {
            return MyFormID(tocheck, DateTime.Now);
        }

        private KeyValuePair<string, FieldValue> GetField(string name)
        {
            foreach (KeyValuePair<string, FieldValue> s in formfields)
                if (name == s.Key)
                    return s;
            throw new FieldNotFoundException(name);
        }

        private string[] _formID;
        /// <summary>
        /// _formID[0] is the "canonical" name of the form
        /// </summary>
        /// <remarks>No way to remove a form alias once it's created</remarks>
        public string formID
        {
            get
            {
                return _formID[0];
            }
            private set
            {
                _formID[_formID.Length] = value;
            }
        }

        private Dictionary<string, FieldValue> formfields;

        private static Dictionary<string, Form> _formlookup;
        private static Receipt[] _receipt = { null };
        private DateTime initiationdate;
        private DateTime expirationdate;

        public Form()
        { }

        /// <summary>
        /// Generates a clerk's signature on the Form, creating Receipt
        /// </summary>
        /// <remarks>
        /// This is the granddaddy.  This makes the thing that, after 
        /// Glance() passes, is generated -- the Clerk's signature is a
        /// receipt, and can be used to obtain the information associated 
        /// in the future, if/when necessary.
        /// 
        /// All clerks create records, and it's often the case that copies
        /// of the records that they create, after they've made their
        /// official marks on them, are the receipts that are given.  (Other
        /// clerks handle money, and provide a receipt which is often a
        /// carbonless copy of the signed receipt, or a photocopy of the
        /// receipt-as-paid (for real estate, for example.)  Not every
        /// transaction requires this, and it's important to recognize that the 
        /// receipt can and will often be detached from the transaction data.
        /// 
        /// The RecordVault is what handles the actual transaction through 
        /// the entire process.  It logs -everything- that it does.  Its
        /// workflow rules are what send items to other systems for
        /// verification, etc -- the Clerk here is simplified, and is more
        /// akin to a teller than anything.
        /// </remarks>
        /// <param name="submission">The filled-in Form</param>
        /// <returns></returns>
        internal static Receipt CreateReceipt(Form submission)
        {
            // TODO change toSign to something else
            byte[] toSign = Canonize(submission);
#if true
            return new Receipt(toSign); // TODO: Fix this
#else
            byte[] dateStamp = DateStamp.GetDateStamp(toSign);
            byte[] temp = Utility.ConcatBlobs(toSign, timeStamp);
            byte[] clerkSignature = Utility.GenerateSignature(temp);
            _receipt = Utility.ConcatBlobs(temp,clerkSignature);
            RecordVault.Add(receipt);
            return _receipt;
#endif
        }

        /// <summary>
        /// Clone the receipt into a new Form
        /// </summary>
        /// <remarks>
        /// This is to make a new form exactly like the original Template
        /// for demos and debugging and such.
        /// </remarks>
        /// <param name="template">the receipt to deserialize</param>
        public Form(Receipt template)
        {
            Form newform;
        }

        internal static void Register(string p)
        {
            throw new NotImplementedException();
        }
    }
}